#include "slave_timer_reqlist.h"

#include "../base/th.h"
#include "../base/map.h"
#include "../base/list.h"

#include <assert.h>

C_CODE_BEGIN

struct slave_timer_reqlist_storage {
	struct slave_timer_req_runtime rt;
	/* this area will be only accessed by the callback thread */
	bool remove;
};

struct slave_timer_reqlist {
	struct map* dict;
	struct list* reqlist;
	/* using spinlock since the operation shuold be locked is very quick and small */
	spinlock splk;
};

struct slave_timer_reqlist* _reqlist_create( size_t size ) {
	struct slave_timer_reqlist* reqlist = malloc(sizeof(struct slave_timer_reqlist));
	reqlist->dict =map_create(sizeof(struct slave_timer_reqlist_storage*),20,NULL);
	reqlist->reqlist= list_create(sizeof(struct slave_timer_reqlist_storage),20);
	thread_spinlock_create(&(reqlist->splk));
	return reqlist;
}

void _reqlist_destroy( struct slave_timer_reqlist* rl ) {
	map_destroy(rl->dict);
	list_destroy(rl->reqlist);
	thread_spinlock_destroy(&(rl->splk));
	free(rl);
}

struct  slave_timer_req_runtime* _reqlist_query( struct slave_timer_reqlist* reql, const char* src ){
	void* val = map_query(reql->dict,src,NULL);
	struct slave_timer_reqlist_storage* req_storage;
	if(val == NULL)
		return NULL;
	req_storage = (struct slave_timer_reqlist_storage*)val;
	return &(req_storage->rt);
}

bool _reqlist_remove( struct slave_timer_reqlist* reql , const char* src ) {
	void* val = map_query(reql->dict,src,NULL);
	bool ret;
	struct slave_timer_reqlist_storage* req_storage;
	if(val == NULL)
		return false;
	req_storage = (struct slave_timer_reqlist_storage*)val;
	req_storage->remove = true;
	/* delete it from the dictionary */
	ret = map_remove(reql->dict,src);
	assert(ret);
	return true;
}

bool _reqlist_insert( struct slave_timer_reqlist* rl, struct slave_timer_req_runtime* rt) {
	void* node;
	void* lnode;
	struct map_kv mkv;
	struct slave_timer_reqlist_storage reqs;
	reqs.rt = *rt;
	reqs.remove=false;
	mkv.key = rt->name;
	/* a trick */
	mkv.val = &node;
	node = map_insert(rl->dict,&mkv,NULL);
	if( node == NULL )
		return false;
	/* ok insert the real stuff */
	thread_spinlock_require(&(rl->splk),false);
	list_push_back(rl->reqlist,&reqs);
	lnode= list_back( rl->reqlist );
	thread_spinlock_release(&(rl->splk));
	assert(lnode);
	/* fix the map value associated to the key */
	*(void**)(node) = lnode;
	return true;
}

void* _reqlist_begin_iterator( struct slave_timer_reqlist* reqlist ) {
	void* begin;
	void* end = list_tail(reqlist->reqlist);
	void* temp;
	struct slave_timer_reqlist_storage* storage;
	thread_spinlock_require(&(reqlist->splk),false);
	begin = list_head(reqlist->reqlist);
	while( begin != end ) {
		storage = (struct slave_timer_reqlist_storage*)(begin);
		if(storage->remove) {
			/* remove this iterator */
			temp = begin;
			begin = list_move_list_node(1,begin,reqlist->reqlist);
			list_erase(reqlist->reqlist,temp);
		}else{
			break;
		}
	}
	thread_spinlock_release(&(reqlist->splk));
	return begin;
}

void* _reqlist_end_iterator( struct slave_timer_reqlist* reqlist ) {
	return list_tail(reqlist->reqlist);
}

void* _reqlist_move_iterator( struct slave_timer_reqlist* reqlist , void* node ) {
	void* end = list_tail(reqlist->reqlist);
	void* temp;
	struct slave_timer_reqlist_storage* storage;
	thread_spinlock_require(&(reqlist->splk),false);
	while( node != end ) {
		storage = (struct slave_timer_reqlist_storage*)(node);
		if(storage->remove) {
			/* remove this iterator */
			temp = node;
			node = list_move_list_node(1,node,reqlist->reqlist);
			list_erase(reqlist->reqlist,temp);
		}else{
			break;
		}
	}
	thread_spinlock_release(&(reqlist->splk));
	return node;
}

struct slave_timer_req_runtime* _reqlist_deref_iterator( void* n ) {
	return &(((struct slave_timer_reqlist_storage*)(n))->rt);
}

C_CODE_END